﻿/*------------------------------------------------------------------------

RENDERUNIT.HPP v1.0.7

Copyright 楊志賢 CxxlMan, 2012 - 2014
All Rights Reserved

------------------------------------------------------------------------*/



#if !defined(__RENDERUNIT_HPP_Cxxl3D)
#define __RENDERUNIT_HPP_Cxxl3D

#include <Sys\RENDERUNITREG.HPP>


namespace Cxxl3D
{

class IDatagramDisposal;

// IDatagramDisposal 寄存在 IDepositStore 的資料
class IDDDeposit:public CxxlMan::cxxlObject
{
public:
  // Constructor
  IDDDeposit()
    :cxxlObject(CxxlMan::Spirit_Easy)
  {}

  // Destructor
  virtual ~IDDDeposit()
  {}

  // 取得實作類別，為了避免轉形太花時間
  virtual void *GetInstance() = 0;
};

// IRenderDatagram 的延伸類別若要提供 IDDDeposit 的寄存功能，應再繼承此類別
class DepositStore:virtual public CxxlMan::cxxlPreserve2
{
  CxxlMan::Smart_Ptr<IDDDeposit> m_IDDDeposit_Ptr;
  IDatagramDisposal *m_pIdentification; // 用於辨識 m_IDDDeposit_Ptr 是誰存放的

  CxxlMan::Smart_Ptr<IDDDeposit> cxxlFASTCALL GetDeposit(IDatagramDisposal *pIdentification_Arg)
  {
    CxxlMan::CriticalSecHandle AutoCSH(csPreserve);

    if(pIdentification_Arg != m_pIdentification)
    {
      m_pIdentification = NULL;
      m_IDDDeposit_Ptr.Destroy();
      haveClearDepositEvent();
    }
    
    return m_IDDDeposit_Ptr;
  }

  void cxxlFASTCALL SetDeposit(const CxxlMan::Smart_Ptr<IDDDeposit> &IDDDeposit_Arg, IDatagramDisposal *pIdentification_Arg)
  {
    csPreserve.Enter();
    m_IDDDeposit_Ptr = IDDDeposit_Arg;
    m_pIdentification = pIdentification_Arg;
    csPreserve.Leave();
    haveSetDepositEvent();
  }

protected:
  // 給延伸類別清除 IDDDeposit_Arg 用 
  void cxxlFASTCALL ClearDeposit()
  {
    csPreserve.Enter();
    m_IDDDeposit_Ptr.Destroy();
    m_pIdentification = NULL;
    csPreserve.Leave();
    haveClearDepositEvent();
  }

  // 當 SetDeposit() 呼叫之後，會被叫用
  virtual void cxxlFASTCALL haveSetDepositEvent() = 0;

  // 當 Deposit 被清除呼叫之後，會被叫用
  virtual void cxxlFASTCALL haveClearDepositEvent() = 0;

public:
  // Constructor
  DepositStore()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(L""), // 在建構時指定 ClassID
    m_IDDDeposit_Ptr(NULL,this)
  {
    m_pIdentification = NULL;
  }

  // Destructor
  virtual ~DepositStore()
  {
  }

  friend class IDatagramDisposal;
};

// 要放入 IRenderPipe 的物件介面，主要用於內含 3D 物件資料
class IRenderDatagram:virtual public CxxlMan::cxxlPreserve2
{
  // 同步處理，給 class IDatagramDisposal 叫用
  void cxxlFASTCALL IRenderDatagramLock()
  {
    csPreserve.Enter();
  }
  void cxxlFASTCALL IRenderDatagramUnLock()
  {
    csPreserve.Leave();
  }

  // 這裡須傳回 IRenderDatagram 的 "實作介面"，即被 cxxlCM_GetElement() 叫用的 InterfaceID
  virtual CxxlMan::UNICODE_String cxxlFASTCALL GetRenderDatagramID() const = 0;

  // 傳回 IRenderDatagram 的 "實作介面"
  virtual void *cxxlFASTCALL GetDefaultInterface()  = 0;


protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && cxxlPreserve2::Ref(F))
      return true;
    else
      return false;
  }

public:
  // Constructor
  IRenderDatagram()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(L"") // 在建構時指定 ClassID    
  {
    
  }

  // Destructor
  virtual ~IRenderDatagram()
  {}

  // 若是 class IGroupRD 會回覆 true 
  virtual bool cxxlFASTCALL isGroup() const
  {
    return false;
  }


  friend class CxxlMan::IcxxlStorage;          // Preserve2 元件須加上這個
  friend class CxxlMan::Smart_Ptr<IRenderDatagram>;  // Preserve2 元件須加上這個

  friend class IDatagramDisposal;
};


// 和 IRenderDatagram 對應，實際處理渲染到 3D 引擎的介面，須依不同的 3D 引擎實作
class IDatagramDisposal:virtual public CxxlMan::cxxlObject
{
protected:

  // 以下提供橋接能力

  // 同步處理，給 class IDatagramDisposal 叫用
  void cxxlFASTCALL Lock(const CxxlMan::Smart_Ptr<IRenderDatagram> &rd_Arg)
  {
    rd_Arg->IRenderDatagramLock();
  }
  void cxxlFASTCALL UnLock(const CxxlMan::Smart_Ptr<IRenderDatagram> &rd_Arg)
  {
    rd_Arg->IRenderDatagramUnLock();
  }

  // 這裡須傳回 IRenderDatagram 的 "實作介面"，即被 cxxlCM_GetElement() 叫用的 InterfaceID
  CxxlMan::UNICODE_String cxxlFASTCALL GetRenderDatagramID(const CxxlMan::Smart_Ptr<IRenderDatagram> &rd_Arg) const
  {
    return rd_Arg->GetRenderDatagramID();
  }

  // 傳回 IRenderDatagram 的 "實作介面"
  virtual void *cxxlFASTCALL GetDefaultInterface(const CxxlMan::Smart_Ptr<IRenderDatagram> &rd_Arg) const
  {
    return rd_Arg->GetDefaultInterface();
  }

  CxxlMan::Smart_Ptr<IDDDeposit> cxxlFASTCALL GetDeposit(const CxxlMan::Smart_Ptr<DepositStore> &ds_Arg)
  {
    return ds_Arg->GetDeposit(this);
  }

  void cxxlFASTCALL SetDeposit(const CxxlMan::Smart_Ptr<IDDDeposit> &IDDDeposit_Arg, const CxxlMan::Smart_Ptr<DepositStore> &ds_Arg)
  {
    ds_Arg->SetDeposit(IDDDeposit_Arg, this);
  }


public:
  // Constructor
  IDatagramDisposal()
    :cxxlObject(CxxlMan::Spirit_Easy)
  {
  }

  // Destructor
  virtual ~IDatagramDisposal()
  {}
};



// 為 IRenderDatagram 元件註冊
inline void IRenderDatagram_Init()
{
  RenderUnit_Reg(UNITEXTNAME, IRenderDatagram_Group);
}


} /* namespace Cxxl3D */
#endif
